Lua templating/Converting Wikitext templates
Collected here are tips for converting Wikitext templates to Lua. Switch statements One of the most common cases of a slow template is due to a large statement, which are often called multiple times on the same page. By making use of mw.loadData and a simple table of data, we can make these templates significantly faster. By using a simple Lua table of data, we move to using a roughly O(1) hash table lookup, and by using mw.loadData(), the data will only be loaded once in a page load no matter how many times Module:FooBar is invoked on a page. For a switch statement with 150 items, converting it to Lua in this way resulted in an approximately 50% improvement in parse time. For example, if you have a template that uses a switch statement like so: } | case 1 = Foo | case 2 = Bar | case 3 | case 4 = FooBar | #default: } }} To convert it to Lua, create two module pages. Module:FooBar: local p = {} local fooBarData = mw.loadData( 'Module:FooBar/data' ) function p.fooBar( frame ) local fooBarText = frame.args1 if fooBarDatafooBarText ~= nil then fooBarText = fooBarDatafooBarText end return fooBarText end return p Module:FooBar/data: local fooBarData = { 1" = "Foo", 2" = "Bar", 3" = "FooBar", 4" = "FooBar", } return fooBarData Conditional statements (#if) Many templates make use of "#if" parser functions resulting in a lot of nested functions, which may make the code very complex and hard to understand. This can be converted and made more efficient using . See live demo. For example, to create template that checks if a template argument contains "text", one would write something like: }|You entered text|No text}} This can be converted to: Module:if : local p = {} function p.main( frame ) local tArgs = frame:getParent() if not(tArgs.args1) then tArgs = frame end local sText = tArgs.args1 local sTrueAction = tArgs.args2 or tArgs.args"true" local sFalseAction = tArgs.args3 or tArgs.args"false" if sText nil or sText "" then sText = mw.getCurrentFrame():preprocess(sTrueAction) else sText = mw.getCurrentFrame():preprocess(sFalseAction) end return sText end return p This can be applied to complex "#if" based parser functions, and would be much easier to understand. Check if article exists (#ifexists) Create Module:ifexists : local p = {} function p.exists( frame ) local tArgs = frame:getParent() if not(tArgs.args1) then tArgs = frame end local sText = tArgs.args1 local sTrueAction = tArgs.args2 or tArgs.args"true" local sFalseAction = tArgs.args3 or tArgs.args"false" if sText nil or sText "" then if mw.title.new( sText ).exists then return sTrueAction else return sFalseAction end end end return p Then simply use . Note: This sadly still remains an expensive function. Loop Statements (#for) One way to reduce the template size, and to make it load faster and more efficiently is to reduce repeated text. This can typically be achieved by using loops or using Lua. A template that repeats some text can be created using the loops extension by writing: Calling template foo : } | } ♣ }} Will result in the text: a♣b♣c♣d♣ This can be converted to Module:loop: local p = {} function p.appendloop( frame ) local tArgs = frame:getParent() if not(tArgs.args1) then tArgs = frame end local sOutputText = "" for iKey,sValue in pairs(tArgs.args) do sOutputText = sOutputText .. sValue .. "♣" end return sOutputText end return p Template:foo : This shows the date, e.g. 2013-10-04. The special characters used to get these date can be found in the lua's page. See also *Comparable Lua functions to wikitext Converting Wikitext templates